package fr.lteconsulting.hexa.rebind; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import com.google.gwt.core.ext.Generator; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JParameter; import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.JTypeParameter; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import fr.lteconsulting.hexa.client.comm.Cache; import fr.lteconsulting.hexa.client.comm.FieldName; public class ServiceGenerator extends Generator { // @SuppressWarnings("unused") GeneratorContext context = null; private TreeLogger logger = null; private TypeOracle typeOracle = null; private SourceWriter sw = null; String requestedClassName; String createdClassName; String fullCreatedClassName; String packageName; int currentNumber = 0; HashSet<JType> dataProxyFastFactories; ArrayList<OnResponseCallbackInfo> onResponseCallbacks; HashMap<String, JClassType> proxiesToGenerate; Map<String, JType> marshallsToGenerate; @Override public String generate( TreeLogger logger, GeneratorContext context, String requestedClass ) throws UnableToCompleteException { this.logger = logger; logger.log( TreeLogger.INFO, "Generate '" + requestedClass, null ); this.context = context; typeOracle = context.getTypeOracle(); JClassType requestedType = typeOracle.findType( requestedClass ); if( requestedType == null ) { logger.log( TreeLogger.ERROR, "Type '" + requestedClass + "' has not been found by the Oracle", null ); throw new UnableToCompleteException(); } proxiesToGenerate = new HashMap<String, JClassType>(); marshallsToGenerate = new HashMap<String, JType>(); onResponseCallbacks = new ArrayList<OnResponseCallbackInfo>(); dataProxyFastFactories = new HashSet<JType>(); requestedClassName = requestedType.getName(); createdClassName = requestedClassName + "Impl"; fullCreatedClassName = requestedClass + "Impl"; packageName = requestedType.getPackage().getName(); PrintWriter printWriter = context.tryCreate( logger, packageName, createdClassName ); if( printWriter == null ) { // logger.log( TreeLogger.INFO, requestedClass + // " : CANNOT CREATE PRINT WRITER", null ); return fullCreatedClassName; } ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( packageName, createdClassName ); composerFactory.setSuperclass( "ServiceBase" ); composerFactory.addImplementedInterface( requestedClass ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.ServiceBase" ); composerFactory.addImport( "java.util.ArrayList" ); composerFactory.addImport( "java.util.List" ); composerFactory.addImport( "java.util.HashMap" ); composerFactory.addImport( "java.util.Iterator" ); composerFactory.addImport( "java.util.Map.Entry" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.GenericJSO" ); composerFactory.addImport( "com.google.gwt.core.client.JavaScriptObject" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.DataProxy" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.Service" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.RequestDesc" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.RPCProxy" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.AcceptsRPCRequests" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.ResponseJSO" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.JSArrayIterator" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.JSOArrayInteger" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.XRPCProxy" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.interfaces.ITablesManager" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.interfaces.IAsyncCallback" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.XRPCRequest" ); composerFactory.addImport( "com.google.gwt.core.client.GWT" ); composerFactory.addImport( "com.google.gwt.core.client.JsArray" ); composerFactory.addImport( "com.google.gwt.core.client.JsArrayInteger" ); composerFactory.addImport( "com.google.gwt.core.client.JsArrayString" ); composerFactory.addImport( "com.google.gwt.http.client.URL" ); composerFactory.addImport( "com.google.gwt.user.client.Window" ); composerFactory.addImport( "com.google.gwt.user.client.rpc.AsyncCallback" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaDate" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaTime" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaDateTime" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.FactoredInterface" ); composerFactory.addImport( "com.google.gwt.json.client.JSONValue" ); composerFactory.addImport( "com.google.gwt.json.client.JSONObject" ); composerFactory.addImport( "com.google.gwt.json.client.JSONArray" ); composerFactory.addImport( "com.google.gwt.json.client.JSONString" ); composerFactory.addImport( "com.google.gwt.json.client.JSONNumber" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.callparams.ListMarshall" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.callparams.SetMarshall" ); composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.callparams.MapMarshall" ); sw = composerFactory.createSourceWriter( context, printWriter ); if( sw == null ) { // sw==null: already generated // logger.log( TreeLogger.ERROR, requestedClass + // " : CANNOT CREATE SOURCEWRITER", null ); return fullCreatedClassName; } JMethod[] methods = requestedType.getMethods(); String interfaceChecksum = generateChecksum( methods ); // generate server com initialisation method sw.println( "public void Init( AcceptsRPCRequests server )" ); sw.println( "{" ); sw.println( " setConfig( server, \"" + interfaceChecksum + "\" );" ); sw.println( "}" ); sw.println(); for( int i = 0; i < methods.length; i++ ) { generateMethod( requestedClassName, interfaceChecksum, methods[i], i ); sw.println(); } generateCallParamMarshalls(); generateOnResponseCallbacks(); generateDataProxyFastJSOClasses(); generateProxies(); sw.commit( logger ); // Generate the PHP interop service interface file OutputStream phpStream = context.tryCreateResource( logger, requestedClassName + ".interface.php" ); if( phpStream != null ) { PrintWriter phpPw = new PrintWriter( phpStream ); generatePHP( phpPw, requestedType, interfaceChecksum ); phpPw.flush(); context.commitResource( logger, phpStream ); } // Generate the PHP interop service interface file String javaInterfaceName = requestedClassName + "ServerSide"; OutputStream javaStream = context.tryCreateResource( logger, javaInterfaceName + ".java" ); if( javaStream != null ) { PrintWriter javaPw = new PrintWriter( javaStream ); generateJavaInterface( javaPw, javaInterfaceName, requestedType, interfaceChecksum ); javaPw.flush(); context.commitResource( logger, javaStream ); } return fullCreatedClassName; } private String generateChecksum( JMethod[] methods ) { StringBuilder b = new StringBuilder(); for( int i = 0; i < methods.length; i++ ) b.append( methods[i].getJsniSignature() ); return String.valueOf( Math.abs( b.toString().hashCode() ) ); } private void generatePHP( PrintWriter w, JClassType requestedType, String interfaceChecksum ) { w.println( "<?php" ); w.println(); JMethod[] methods = requestedType.getMethods(); w.println( "function _gwtio_get_" + requestedClassName + "_CheckSum() { return \"" + interfaceChecksum + "\"; }" ); w.println(); w.println( "function _gwtio_get_" + requestedClassName + "_ServiceMethods() { return array( " ); for( JMethod method : methods ) { w.println( " '" + method.getName() + "'," ); } w.println( "); }" ); w.println(); w.println( "interface I" + requestedClassName ); w.println( "{" ); for( JMethod method : methods ) { JParameter[] params = method.getParameters(); JClassType cbType = typeOracle.findType( params[params.length - 1].getType().getQualifiedSourceName() ); if( cbType == null ) { w.println( "*** ERROR : Unable to find callback type : " + params[params.length - 1].getType().getQualifiedSourceName() ); return; } w.println( " // " + params[params.length - 1].getType().getParameterizedQualifiedSourceName() ); w.print( " public function " + method.getName() + "( " ); for( int p = 0; p < params.length - 1; p++ ) { w.print( "$" + params[p].getName() ); if( p < params.length - 2 ) w.print( ", " ); } w.println( " );" ); // w.println( " }" ); w.println(); } w.println( "}" ); w.println(); w.println( "?>" ); } private void generateJavaInterface( PrintWriter w, String javaInterfaceName, JClassType requestedType, String interfaceChecksum ) { w.println( "public interface " + javaInterfaceName ); w.println( "{" ); w.println(); w.println( "public static final String CHECKSUM = \"" + interfaceChecksum + "\";" ); w.println(); JMethod[] methods = requestedType.getMethods(); w.println( "public static final String[] METHODS = new String[] {" ); for( int i = 0; i < methods.length; i++ ) w.println( (i > 0 ? ", " : "") + "\"" + methods[i].getName() + "\"" ); w.println( "};" ); for( JMethod method : methods ) { JParameter[] params = method.getParameters(); JClassType cbType = typeOracle.findType( params[params.length - 1].getType().getQualifiedSourceName() ); if( cbType == null ) { w.println( "*** ERROR : Unable to find callback type : " + params[params.length - 1].getType().getQualifiedSourceName() ); return; } JType returnType = params[params.length - 1].getType(); JParameterizedType returnTypeParametrized = returnType.isParameterized(); if( returnTypeParametrized == null ) { logger.log( Type.WARN, "When generating method " + method.getName() + " for server side service interface " + requestedType.getName() + ", return type was not found. This method will not be declared for the server." ); continue; } JClassType[] returnTypeTypeParameters = returnTypeParametrized.getTypeArgs(); assert returnTypeTypeParameters.length == 1; String returnTypeName = returnTypeTypeParameters[0].getParameterizedQualifiedSourceName(); w.print( " public " + returnTypeName + " " + method.getName() + "( " ); for( int p = 0; p < params.length - 1; p++ ) { w.print( params[p].getType().getParameterizedQualifiedSourceName() + " " + params[p].getName() ); if( p < params.length - 2 ) w.print( ", " ); } w.println( " );" ); w.println(); } w.println( "}" ); } private String genMethodPrototype( JMethod method ) { StringBuilder sb = new StringBuilder(); sb.append( "public " ); // if the method is type parameterized, echo the type specification JTypeParameter[] typeParams = method.getTypeParameters(); if( typeParams.length > 0 ) { sb.append( "<" ); for( int i = 0; i < typeParams.length; i++ ) { JTypeParameter tp = typeParams[i]; sb.append( tp.getQualifiedSourceName() ); if( i < typeParams.length - 1 ) sb.append( ", " ); } sb.append( ">" ); } sb.append( " void " + method.getName() + "( " ); for( int i = 0; i < method.getParameters().length; i++ ) { JParameter param = method.getParameters()[i]; sb.append( param.getType().getParameterizedQualifiedSourceName() + " " + param.getName() ); if( i < method.getParameters().length - 1 ) sb.append( ", " ); } sb.append( " )" ); return sb.toString(); } private String getParamMarshall( JType type ) { JPrimitiveType prType = type.isPrimitive(); if( prType != null ) { if( prType == JPrimitiveType.INT ) return "intMarshall"; else if( prType == JPrimitiveType.DOUBLE ) return "doubleMarshall"; else if( prType == JPrimitiveType.BOOLEAN ) return "booleanMarshall"; } if( type.getSimpleSourceName().equals( "Integer" ) ) return "intMarshall"; if( type.getSimpleSourceName().equals( "Double" ) ) return "doubleMarshall"; if( type.getSimpleSourceName().equals( "Boolean" ) ) return "booleanMarshall"; if( type.getSimpleSourceName().equals( "String" ) ) return "stringMarshall"; if( type.getSimpleSourceName().equals( "HexaDate" ) ) return "dateMarshall"; if( type.getSimpleSourceName().equals( "HexaTime" ) ) return "timeMarshall"; if( type.getSimpleSourceName().equals( "HexaDateTime" ) ) return "dateTimeMarshall"; if( implementsInterface( type, "ITable" ) ) return "itableMarshall"; if( isJSOType( type ) ) return "jsoMarshall"; if( implementsInterface( type, "java.util.Map" ) ) { // find the marshall name for that type JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 2); String marshallName = "marshall_map_" + paramType[0].getSimpleSourceName() + "_" + paramType[1].getSimpleSourceName(); // register that marshall if( !marshallsToGenerate.containsKey( marshallName ) ) marshallsToGenerate.put( marshallName, type ); // return the name of that marshall return marshallName; } // replace that with : when type implements java.util.List if( implementsInterface( type, "java.util.List" ) ) { // find the marshall name for that type JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 1); String marshallName = "marshall_list_" + paramType[0].getSimpleSourceName(); // register that marshall if( !marshallsToGenerate.containsKey( marshallName ) ) marshallsToGenerate.put( marshallName, type ); // return the name of that marshall return marshallName; } // replace that with : when type implements java.util.Set if( implementsInterface( type, "java.util.Set" ) ) { // find the marshall name for that type JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 1); String marshallName = "marshall_set_" + paramType[0].getSimpleSourceName(); // register that marshall if( !marshallsToGenerate.containsKey( marshallName ) ) marshallsToGenerate.put( marshallName, type ); // return the name of that marshall return marshallName; } return null; } private void generateCallParamMarshalls() { for( Entry<String, JType> e : marshallsToGenerate.entrySet() ) { String marshallName = e.getKey(); JType type = e.getValue(); if( implementsInterface( type, "java.util.Map" ) ) { JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 2); JType keyType = paramType[0]; String keyTypeName = keyType.getParameterizedQualifiedSourceName(); JType valueType = paramType[1]; String valueMarshallName = getParamMarshall( valueType ); sw.println( "MapMarshall<" + keyTypeName + "," + valueType.getParameterizedQualifiedSourceName() + "> " + marshallName + " = new MapMarshall<" + keyTypeName + "," + valueType.getParameterizedQualifiedSourceName() + ">( " + valueMarshallName + " );" ); } else if( implementsInterface( type, "java.util.List" ) ) { JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 1); JType subType = paramType[0]; String subMarshallName = getParamMarshall( subType ); sw.println( "ListMarshall<" + subType.getParameterizedQualifiedSourceName() + "> " + marshallName + " = new ListMarshall<" + subType.getParameterizedQualifiedSourceName() + ">( " + subMarshallName + " );" ); } else if( implementsInterface( type, "java.util.Set" ) ) { JClassType[] paramType = type.isParameterized().getTypeArgs(); assert (paramType.length == 1); JType subType = paramType[0]; String subMarshallName = getParamMarshall( subType ); sw.println( "SetMarshall<" + subType.getParameterizedQualifiedSourceName() + "> " + marshallName + " = new SetMarshall<" + subType.getParameterizedQualifiedSourceName() + ">( " + subMarshallName + " );" ); } else { sw.println( "ERROR : CANNOT GENERATE MARSHALL WITH NAME " + marshallName + " / " + type.getQualifiedSourceName() ); JClassType c = type.isClassOrInterface(); if( c != null ) { JType[] interfaces = c.getImplementedInterfaces(); for( int i = 0; i < interfaces.length; i++ ) sw.println( interfaces[i].getQualifiedSourceName() ); } } } } private boolean implementsInterface( JType type, String interfaceName ) { if( type.getQualifiedSourceName().equals( interfaceName ) ) return true; JClassType c = type.isClassOrInterface(); if( c != null ) { JType[] interfaces = c.getImplementedInterfaces(); for( int i = 0; i < interfaces.length; i++ ) if( interfaces[i].getSimpleSourceName().equals( interfaceName ) || interfaces[i].getQualifiedSourceName().equals( interfaceName ) ) return true; return false; } return false; } // returns true if need to urlencode the string private String paramToString( JParameter param ) { JType type = param.getType(); // get marshall name String marshall = getParamMarshall( type ); if( marshall != null ) return marshall + ".marshall( " + param.getName() + " )"; return "*** ERROR : The service method parameter cannot be marshalled : " + type.getQualifiedSourceName(); } private void generateMethod( String service, String interfaceChecksum, JMethod method, int methodOrdinal ) { JParameter[] params = method.getParameters(); // Use cache annotation to manage the cache Cache cacheAnnotation = method.getAnnotation( Cache.class ); String fUseCache = "true"; if( cacheAnnotation != null ) fUseCache = cacheAnnotation.useCache() ? "true" : "false"; String fInvalidateCache = "false"; if( cacheAnnotation != null ) fInvalidateCache = cacheAnnotation.inv() ? "true" : "false"; // writes the method prototype sw.println( genMethodPrototype( method ) ); sw.println( "{" ); sw.indent(); // writes the code to marshall the called method parameters sw.println( "JSONArray call_params = new JSONArray();" ); for( int i = 0; i < params.length - 1; i++ ) // last param is the callback sw.println( "call_params.set( " + i + ", " + paramToString( params[i] ) + " );" ); // writes the code to create the request description object sw.println( "RequestDesc desc = new RequestDesc( \"" + service + "\", \"" + interfaceChecksum + "\", " + methodOrdinal + ", call_params );" ); sw.println( "desc.setExtraInfo( \"" + method.getName() + "\" );" ); // register and get the name of the callback to use String onResponseCallback = registerOnResponseCallback( params[params.length - 1].getType() ); // writes the code to call the cached server sw.println(); sw.println( "srv.sendRequest( " + fUseCache + ", " + fInvalidateCache + ", desc, callback, " + onResponseCallback + ");" ); sw.outdent(); sw.println( "}" ); } class OnResponseCallbackInfo { String callbackName; JType callbackType; OnResponseCallbackInfo( JType callbackType ) { this.callbackType = callbackType; callbackName = "onResponseCallback_" + (currentNumber++); } public boolean isFor( JType callbackType ) { if( callbackType.getParameterizedQualifiedSourceName().compareTo( this.callbackType.getParameterizedQualifiedSourceName() ) != 0 ) return false; return true; } } String getDataProxyFastImplSimpleName( JType dataProxyFastType ) { return dataProxyFastType.getSimpleSourceName() + "Jso"; } String getDataProxyFastImplName( JType dataProxyFastType ) { return dataProxyFastType.getQualifiedSourceName() + "Jso"; } String getDataProxyFastImplPackageName( JType dataProxyFastType ) { String full = dataProxyFastType.getQualifiedSourceName(); int toRemove = dataProxyFastType.getSimpleSourceName().length() + 1; return full.substring( 0, full.length() - toRemove ); } String registeredDataFastJSOType( JType dataProxyFastType ) { if( dataProxyFastFactories.contains( dataProxyFastType ) ) return getDataProxyFastImplName( dataProxyFastType ); sw.println( "// REGISTERED DATA PROXY FAST TYPE " + dataProxyFastType.getParameterizedQualifiedSourceName() ); dataProxyFastFactories.add( dataProxyFastType ); return getDataProxyFastImplName( dataProxyFastType ); } // TODO everything void generateDataProxyFastJSOClasses() { for( JType type : dataProxyFastFactories ) { String jsoPackage = getDataProxyFastImplPackageName( type ); String jsoSimpleClassName = getDataProxyFastImplSimpleName( type ); PrintWriter pw2 = context.tryCreate( logger, jsoPackage, jsoSimpleClassName ); if( pw2 == null ) continue; ClassSourceFileComposerFactory cf2 = new ClassSourceFileComposerFactory( jsoPackage, jsoSimpleClassName ); cf2.addImport( "fr.lteconsulting.hexa.client.comm.GenericJSO" ); cf2.addImport( "com.google.gwt.core.client.JavaScriptObject" ); cf2.addImport( "com.google.gwt.core.client.GWT" ); cf2.addImport( "fr.lteconsulting.hexa.client.tools.HexaTools" ); cf2.addImplementedInterface( type.getParameterizedQualifiedSourceName() ); cf2.setSuperclass( "GenericJSO" ); SourceWriter sw2 = cf2.createSourceWriter( context, pw2 ); generateDataProxyFastJSOImpl( jsoSimpleClassName, type, sw2, logger ); sw2.commit( logger ); } } void generateDataProxyFastJSOImpl( String className, JType type, SourceWriter sw, TreeLogger logger ) { sw.println( "protected " + className + "() {}" ); JClassType clazz = type.isInterface(); for( JMethod m : clazz.getMethods() ) { FieldName fnAnnotation = m.getAnnotation( FieldName.class ); assert (fnAnnotation != null) : "DataProxyFast factory needs FieldName annotation"; sw.println( "public final " + m.getReturnType().getParameterizedQualifiedSourceName() + " " + m.getName() + "()" ); sw.println( "{" ); sw.indent(); if( m.getReturnType().getSimpleSourceName().equals( "int" ) ) sw.println( "return getInt( \"" + fnAnnotation.fieldName() + "\" );" ); else if( m.getReturnType().getSimpleSourceName().equals( "String" ) ) sw.println( "return getString( \"" + fnAnnotation.fieldName() + "\" );" ); sw.outdent(); sw.println( "}" ); } } /* * * * class DaatDataProxyFastFactory implements * DataProxyFastFactories.IDataProxyFastFactory { class DaatImpl extends * GenericJSO implements Daat { protected DaatImpl() {} * * public final int getId() { return getInt( "field_name" ); } } * * @Override public <T> T getData( JavaScriptObject obj ) { return * (T)((DaatImpl)obj); } } */ String registerOnResponseCallback( JType callbackType ) { for( OnResponseCallbackInfo info : onResponseCallbacks ) if( info.isFor( callbackType ) ) return info.callbackName; OnResponseCallbackInfo info = new OnResponseCallbackInfo( callbackType ); onResponseCallbacks.add( info ); return info.callbackName; } void generateOnResponseCallbacks() { for( OnResponseCallbackInfo info : onResponseCallbacks ) { sw.println(); generateOnResponseCallback( info ); sw.println(); } } void generateOnResponseCallback( OnResponseCallbackInfo info ) { sw.println( "// Callback type : " + info.callbackType.getParameterizedQualifiedSourceName() ); sw.println( "XRPCRequest " + info.callbackName + " = new XRPCRequest() {" ); sw.indent(); generateOnResponseBody( info.callbackType ); sw.outdent(); sw.println( "};" ); } void generateOnResponseBody( JType callbackType ) { sw.println( "public void onResponse(Object cookie, ResponseJSO response, int msgLevel, String msg)" ); sw.println( "{" ); sw.indent(); String cbMethodName = null;// JMethod cbMethod = null; JType[] cbParamTypes = null; assert callbackType != null : "No callback type specified for generating onResponse body"; String cbTypeTxt = callbackType.getQualifiedSourceName(); JClassType cbType = typeOracle.findType( cbTypeTxt ); assert cbType != null : "Cannot find type : " + cbTypeTxt; if( cbType.getSimpleSourceName().equals( "IAsyncCallback" ) ) { JType asyncCallbackType = callbackType; JParameterizedType asyncCallbackPType = asyncCallbackType.isParameterized(); JClassType[] asyncCallbackPTypes = asyncCallbackPType.getTypeArgs(); // logger.log( TreeLogger.WARN, // "Callback interface is IAsyncCallback =>" + // cbType.getParameterizedQualifiedSourceName(), null ); JType cbParamType = asyncCallbackPTypes[0]; // logger.log( TreeLogger.WARN, // "Inside IAsyncCallback is the type =>" + // cbParamType.getParameterizedQualifiedSourceName(), null ); cbParamTypes = new JType[1]; cbParamTypes[0] = cbParamType; cbMethodName = "onSuccess"; } else if( cbType.getMethods().length != 1 ) { if( cbType.getSimpleSourceName().compareTo( "AsyncCallback" ) == 0 ) { JType asyncCallbackType = callbackType; JParameterizedType asyncCallbackPType = asyncCallbackType.isParameterized(); JClassType[] asyncCallbackPTypes = asyncCallbackPType.getTypeArgs(); // logger.log( TreeLogger.WARN, // "Callback interface is AsyncCallback =>" + // cbType.getParameterizedQualifiedSourceName(), null ); JType cbParamType = asyncCallbackPTypes[0]; // logger.log( TreeLogger.WARN, // "Inside AsyncCallback is the type =>" + // cbParamType.getParameterizedQualifiedSourceName(), null ); cbParamTypes = new JType[1]; cbParamTypes[0] = cbParamType; cbMethodName = "onSuccess"; } else { sw.println( "*** ERROR : The callback type has more than one method : " + cbType.getQualifiedSourceName() ); return; } } else { sw.println( "// type of callback is : " + callbackType.getParameterizedQualifiedSourceName() ); JParameterizedType parameterizedType = callbackType.isParameterized();// cbType.isParameterized(); if( parameterizedType != null ) { cbType = callbackType.isClassOrInterface(); JMethod cbMethod = cbType.getMethods()[0]; cbMethodName = cbType.getMethods()[0].getName(); JParameter[] cbParams = cbMethod.getParameters(); cbParamTypes = new JType[cbParams.length]; for( int i = 0; i < cbParams.length; i++ ) cbParamTypes[i] = cbParams[i].getType(); } else { JMethod cbMethod = cbType.getMethods()[0]; cbMethodName = cbMethod.getName(); JParameter[] cbParams = cbMethod.getParameters(); cbParamTypes = new JType[cbParams.length]; for( int i = 0; i < cbParams.length; i++ ) cbParamTypes[i] = cbParams[i].getType(); } } sw.println( "assert response!=null : \"RESPONSE NULL (Callback Type=" + callbackType.getParameterizedQualifiedSourceName() + ") !\";" ); for( int i = 0; i < cbParamTypes.length; i++ ) { String paramTypeName = cbParamTypes[i].getSimpleSourceName(); if( paramTypeName.compareTo( "int" ) == 0 ) { sw.println( "int param" + i + " = response.getInt(" + i + ");" ); } else if( paramTypeName.compareTo( "boolean" ) == 0 ) { sw.println( "boolean param" + i + " = response.getBoolean(" + i + ");" ); } else if( paramTypeName.compareTo( "Integer" ) == 0 ) { sw.println( "Integer param" + i + " = response.getInt(" + i + ");" ); } else if( paramTypeName.compareTo( "Double" ) == 0 ) { sw.println( "Double param" + i + " = response.getDouble(" + i + ");" ); } else if( paramTypeName.compareTo( "String" ) == 0 ) { sw.println( "String param" + i + " = response.getString(" + i + ");" ); } else if( implementsInterface( cbParamTypes[i], "DataProxyFast" ) ) { // TODO register the factory for this type for generating them // later String jsoTypeName = registeredDataFastJSOType( cbParamTypes[i] ); // write code to call the factory sw.println( "// FactoryCall" ); String elementType = cbParamTypes[i].getQualifiedSourceName(); sw.println( elementType + " param" + i + " = (" + jsoTypeName + ") response.getJSO(" + i + ").cast();" ); // sw.println( getDataProxyFastImplName( cbParamTypes[i] ) + // " tmpObj" + i + " = response.getJSO(" + i + ").cast();" ); // sw.println( elementType + " param" + i + " = tmpObj" + i + // ";" ); } else if( paramTypeName.equals( "Iterable" ) ) { JParameterizedType type = cbParamTypes[i].isParameterized(); assert (type != null) : "*** ERROR : An Iterable should have be parametrized : " + cbType.getQualifiedSourceName(); JClassType[] typeArgs = type.getTypeArgs(); assert (typeArgs.length == 1) : "*** ERROR : An Iterable can contain only and at least one type arg : " + cbType.getQualifiedSourceName(); String jsoTypeName = registeredDataFastJSOType( typeArgs[0] ); assert false; sw.println( "// FactoryCall" ); // String elementType = typeArgs[0].getQualifiedSourceName(); sw.println( "Iterable<" + jsoTypeName + "> param" + i + " = new JSArrayIterator<" + jsoTypeName + ">( (JsArray<" + jsoTypeName + ">) (response.getJSO(" + i + ").cast()) );" ); // sw.println( "JsArray<JavaScriptObject> objTmp" + i + // " = response.getJSO(" + i + ").cast();" ); // sw.println( "Iterable<" + elementType + "> param" + i + // " = factory.getList( " + elementType + ".class, objTmp" + i + // " );" ); } else if( implementsInterface( cbParamTypes[i], "java.util.List" ) ) { JParameterizedType type = cbParamTypes[i].isParameterized(); if( type == null ) { sw.println( "*** ERROR : An ArrayList should have be parametrized : " + cbType.getQualifiedSourceName() ); return; } JClassType[] typeArgs = type.getTypeArgs(); if( typeArgs.length != 1 ) { sw.println( "*** ERROR : An ArrayList can contain only and at least one type arg : " + cbType.getQualifiedSourceName() ); return; } JClassType pType = typeArgs[0]; String pTypeName = pType.getSimpleSourceName(); String jsArrayType = null; String jsoGetElemMethod = null; if( pTypeName.compareTo( "Integer" ) == 0 ) { jsArrayType = "JSOArrayInteger"; jsoGetElemMethod = "getArrayInteger"; } else if( pTypeName.compareTo( "Double" ) == 0 ) { jsArrayType = "JSOArrayDouble"; jsoGetElemMethod = "getArrayDouble"; } else if( pTypeName.compareTo( "String" ) == 0 ) { jsArrayType = "JsArrayString"; jsoGetElemMethod = "getArrayString"; } if( jsArrayType != null && jsoGetElemMethod != null ) { sw.println( "ArrayList<" + pTypeName + "> param" + i + " = new ArrayList<" + pTypeName + ">();" ); sw.println( jsArrayType + " jsos" + i + " = response." + jsoGetElemMethod + "(" + i + ");" ); sw.println( "for( int i=0; i<jsos" + i + ".length(); i++ )" ); sw.println( " param" + i + ".add( jsos" + i + ".get(i) );" ); } else { // assume pType is one that is serializable... String elementType = pType.getQualifiedSourceName(); String proxyName = registerProxy( pType ); if( proxyName != null ) sw.println( "List<" + elementType + "> param" + i + " = deserializeArray( response.getArray(" + i + "), " + proxyName + " );" ); } } else if( isJsType( cbParamTypes[i] ) ) { String elementType = cbParamTypes[i].getQualifiedSourceName(); sw.println( elementType + " param" + i + " = (" + elementType + ")(Object)response.getJSO(" + i + ");" ); } else if( isJSOType( cbParamTypes[i] ) ) { String elementType = cbParamTypes[i].getQualifiedSourceName(); sw.println( elementType + " param" + i + " = response.getJSO(" + i + ").cast();" ); } else // if( implementsInterface( cbParamTypes[i], "DataProxy" ) || // implementsInterface( cbParamTypes[i], "DataProxySerialized" ) ) { // assume that the type is serializable... String elementType = cbParamTypes[i].getQualifiedSourceName(); sw.println( elementType + " param" + i + " = null;" ); sw.println( "if( response.getJSO(" + i + ") != null )" ); sw.println( "{" ); sw.println( " param" + i + " = GWT.create( " + elementType + ".class );" ); sw.println( " param" + i + ".init( response.getJSO(" + i + ") );" ); sw.println( "}" ); } // else // { // logger.log( TreeLogger.ERROR, // "Type "+paramTypeName+" has no policy to be returned to the application from the server..." // ); // } if( i < cbParamTypes.length - 1 ) sw.println(); } sw.println(); String prmsTxt = ""; for( int i = 0; i < cbParamTypes.length; i++ ) { prmsTxt = prmsTxt + "param" + i; if( i < cbParamTypes.length - 1 ) prmsTxt = prmsTxt + ", "; } sw.println( "((" + cbType.getSimpleSourceName() + ")cookie)." + cbMethodName + "( " + prmsTxt + " );" ); sw.outdent(); sw.println( "}" ); } String registerProxy( JClassType pType ) { if( isJsType( pType ) ) { sw.println( "ERROR : CANNOT RECEIVE A JAVA LIST OF JSTYPE OBJECT ! " + pType ); return null; } proxiesToGenerate.put( pType.getQualifiedSourceName(), pType ); return getProxyName( pType ); } String getProxyName( JClassType pType ) { return "proxy_" + pType.getSimpleSourceName(); } void generateProxies() { for( Iterator<Entry<String, JClassType>> it = proxiesToGenerate.entrySet().iterator(); it.hasNext(); ) generateProxy( it.next().getValue() ); } void generateProxy( JClassType pType ) { String fullName = pType.getParameterizedQualifiedSourceName(); sw.println( "Proxy<" + fullName + "> " + getProxyName( pType ) + " = new Proxy<" + fullName + ">() {" ); sw.indent(); sw.println( "public " + fullName + " create( GenericJSO jso )" ); sw.println( "{" ); sw.indent(); if( isJSOType( pType ) ) { sw.println( "return jso.cast();" ); } else { sw.println( fullName + " o = GWT.create( " + fullName + ".class );" ); sw.println( "o.init(jso);" ); sw.println( "return o;" ); } sw.outdent(); sw.println( "}" ); sw.outdent(); sw.println( "};" ); sw.println(); } boolean isJsType( JType type ) { JClassType cType = type.isClass(); if( cType == null ) cType = type.isInterface(); if( cType == null ) return false; Annotation[] annotations = cType.getDeclaredAnnotations(); for( Annotation annotation : annotations ) { if( "jsinterop.annotations.JsType".equals( annotation.annotationType().getName() ) ) return true; } return false; } boolean isJSOType( JType type ) { JClassType cType = type.isClass(); if( cType == null ) cType = type.isInterface(); if( cType == null ) return false; for( JClassType t = cType; t != null; t = t.getSuperclass() ) { sw.println( "// supertype : " + t.getSimpleSourceName() ); JTypeParameter typeParam = t.isTypeParameter(); if( typeParam != null ) { sw.println( "// which is a type parameter" ); JClassType[] bounds = typeParam.getBounds(); for( int b = 0; b < bounds.length; b++ ) { sw.println( "// which is bound to : " + bounds[b].getSimpleSourceName() ); if( bounds[b].getSimpleSourceName().compareTo( "JavaScriptObject" ) == 0 ) return true; } } if( t.getSimpleSourceName().compareTo( "JavaScriptObject" ) == 0 ) return true; } return false; } }